"""
连接池

因为硬件资源有限，不断开启和回收大量连接消耗性能，成本高，所以需要使用连接池。

一个简单的连接池
1.连接池是一个容器，用来存放连接。当然可以针对池子预留连接，设置连接数下限或者上限等等，进行调优。
2.有一个工厂方法可以获取连接池的连接，使用完成之后还能把用完的连接返回，供其他调用者使用。
"""

import threading
import logging
import random

FORMAT = "%(thread)d %(threadName)s %(message)s"
logging.basicConfig(level=logging.INFO, format=FORMAT)


class Conn:
    def __init__(self, name):
        self.name = name

# 连接池
class Pool:
    def __init__(self, count):
        self.count = count
        self.s = threading.Semaphore(count)
        # 初始化连接池，连接数为count
        self.pool = [Conn('connect_{}'.format(i)) for i in range(count)]

    def get_conn(self):
        # 向线程池中拿走一个连接
        self.s.acquire()
        data = self.pool.pop()
        return data

    def return_conn(self, conn: Conn):
        # 向线程池中添加一个连接，这里需要注意，release要在append后面。
        self.pool.append(conn)
        self.s.release()


# 初始化线程池
pool = Pool(4)


def worker(pool):
    # 拿走一个连接
    conn = pool.get_conn()
    # 处理
    WaitTime = random.randint(1, 4)
    threading.Event().wait(WaitTime)
    logging.info('conn is {},time is {}'.format(conn, WaitTime))
    # 还原一个连接
    pool.return_conn(conn)


# 模拟调用线程池
for i in range(9):
    threading.Thread(target=worker, args=(pool,), name='work-{}'.format(i)).start()
